# encoding: utf-8
import os
from flask_restplus import Resource
from app.extensions.api import Namespace
from app.extensions import db, log
from app.modules.common.utils import checkToken, DbCommit
from app.modules.entrance.models import EntranceInfo
from . import parameters, schemas
from .models import AppInfo
from app.modules.zones.common import getZoneCodesByCode
from app import BaseConfig
from app.modules.common.jsonFileUtil import getJsonFile
from app.modules.common.schemas import BaseSchema

api = Namespace('apps', description = "应用")  # pylint: disable=invalid-name


@api.route('/')
class GetAppList(Resource):
    @api.parameters(parameters.AppListParameters())
    @api.response(schemas.AppListSchema(many = False))
    @checkToken
    def get(self, args, **kwargs):
        """
        获取应用列表
        :param args:
        :return:
        """
        _env_name = args['env_name']
        _app_name = args['app_name']
        _entrance_types = args['entrance_types']
        _zone_code = args['zone_code']
        _current_status = args['current_status']
        _is_resource = args['is_resource']
        _group = args['group']

        _query = AppInfo.query.filter_by(env_name = _env_name)

        if _app_name is not None:
            _query = _query.filter_by(app_name = _app_name)
        if _entrance_types is not None:
            _query = _query.filter(AppInfo.entrance_type.in_(str(_entrance_types).split(',')))
        if _zone_code is not None:
            _query = _query.filter(AppInfo.zone_code.in_(getZoneCodesByCode(_env_name, zone_code = _zone_code)))
        if _current_status is not None:
            _query = _query.filter(AppInfo.current_status.in_(str(_current_status).split(',')))
        if _is_resource is not None:
            _query = _query.filter_by(is_resource = _is_resource)
        if _group is not None:
            _query = _query.filter_by(group = _group)

        _list = _query.order_by(AppInfo.app_name.asc()).all()

        return {'success': True, 'msg': '', 'data': _list}


@api.route('/update')
class UpdateAppInfo(Resource):
    @api.parameters(parameters.UpdateAppInfoParameters())
    @api.response(BaseSchema(many = False))
    @checkToken
    def get(self, args, **kwargs):
        """
        更新应用信息
        :param args:
        :param kwargs:
        :return:
        """
        _env_name = args['env_name']
        if _env_name is None:
            for _env in BaseConfig.ENV_NAME_LIST:
                import_beetle_apps(_env)
        else:
            import_beetle_apps(_env_name)
        return {'success': True, 'msg': ''}


def import_beetle_apps(env_name):
    """
    导入beetle内保存的app列表
    :return:
    """

    if env_name not in BaseConfig.ENV_NAME_LIST:
        return

    _file = "%s/%s.json" % (BaseConfig.RELEASE_INFO_FILE_PATH, env_name)
    if not os.path.exists(_file):
        return

    _json = getJsonFile(_file)
    _areas = _json['areas']
    for _area in _areas:
        _zone_code = _area['zone_code']
        if _zone_code is None or _zone_code == '':
            continue
        _tasks = _area['tasks']

        _list = []

        for _task in _tasks:
            _app = AppInfo.query.filter_by(app_name = _task['name'], host = _task['ip'], zone_code = _zone_code,
                                           http_port = _task['httpPort'], env_name = env_name).first()
            # 应用不存在时添加 应用存在时更新
            if _app is None:
                add_app_from_task(env_name, _zone_code, _task)
            else:
                update_app_from_task(_app, _task)
            _list.append('%s_%s_%s' % (_task['name'], _task['ip'], _task['httpPort']))

        # 判断是否有修改ip或者httpPort的应用
        del_app(env_name, _zone_code, _list)
        # 更新完应用后，判断是否需要更新uschedule入口信息
        update_uschedule_entrance(env_name, _zone_code)


def add_app_from_task(env_name, zone_code, task):
    log.info('app.modules.apps.resources.add_app_from_task task=%s' % task)
    if task['type'] != 'tomcat' and task['type'] != 'php' and task['type'] != 'spring_boot_jar':
        return
    _type = None
    _info = AppInfo(app_name = task['name'], host = task['ip'], current_status = "GNONE", expect_status = "GNONE",
                    zone_code = zone_code, group = task['group'], env_name = env_name,
                    is_resource = task['is_resource'], http_port = task['httpPort'])

    if task['type'] == 'tomcat' or task['type'] == 'spring_boot_jar':
        _type = 'jmx'
        _info.jmx_port = task['jmx_port']
        _info.app_type = task['type']

        if task['name'] == 'uschedule':
            _info.is_resource = '1'
    elif task['type'] == 'php':
        _type = 'hosts'
        _info.app_type = "php"
        _info.agent_port = task['agent_port']

    _entrance = EntranceInfo.query.filter_by(type = _type, env_name = env_name, zone_code = zone_code).first()
    _info.entrance_id = _entrance.id
    _info.entrance_type = _type

    log.info('app.modules.apps.resources.add_app_from_task _info=%s' % _info.to_dict())
    db.session.add(_info)
    DbCommit()


def update_app_from_task(app, task):
    app.group = task['group']
    app.jmx_port = None
    app.agent_port = None
    if task['type'] == 'tomcat' or task['type'] == 'spring_boot_jar':
        app.jmx_port = task['jmx_port']
    elif task['type'] == 'php':
        app.agent_port = task['agent_port']
    app.is_resource = task['is_resource']
    log.info('app.modules.apps.resources.update_app_from_task %s' % app.to_dict())
    DbCommit()


def update_uschedule_entrance(env_name, zone_code):
    _info = EntranceInfo.query.filter_by(env_name = env_name, zone_code = zone_code, type = 'uschedule').first()
    if _info is not None:
        _app = AppInfo.query.filter_by(env_name = env_name, zone_code = zone_code, app_name = "uschedule",
                                       host = str(_info.hosts).split(':')[0],
                                       http_port = str(_info.hosts).split(':')[1]).first()
        if _app is not None:
            return
        db.session.delete(_info)

    _app = AppInfo.query.filter_by(env_name = env_name, zone_code = zone_code, app_name = "uschedule").first()
    if _app is None:
        DbCommit()
        return
    db.session.add(EntranceInfo(type = "uschedule", env_name = env_name, zone_code = zone_code,
                                hosts = "%s:%s" % (_app.host, _app.http_port), prefix = "uschedule",
                                suffix = "/uschedule/job.do?cmd=open$resetBlackList", expect_status = "GNONE",
                                current_status = "GNONE"))
    DbCommit()


def del_app(env_name, zone_code, _list):
    for _app in AppInfo.query.filter_by(env_name = env_name, zone_code = zone_code).all():
        if _app.app_name in BaseConfig.UPDATE_IGNORE_APP:
            continue
        if '%s_%s_%s' % (_app.app_name, _app.host, _app.http_port) not in _list:
            log.info('app.modules.apps.resources.del_app %s' % _app.to_dict())
            db.session.delete(_app)
    DbCommit()
